package markor.jpa.hello.jpa.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import markor.jpa.hello.jpa.bean.ResponseDTO;
import markor.jpa.hello.jpa.exception.CommonBizException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@ControllerAdvice
@Slf4j
public class MyResponseBodyAdvice implements ResponseBodyAdvice{

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        String method = methodParameter.getMethod().getName();
        methodParameter.getMethod().getAnnotations();
        // 获取正在执行的类的名称
        String name = methodParameter.getExecutable().getDeclaringClass().getName();
        System.out.println("获取正在执行的类的名称 ----" +name);
        System.out.println("获取正在执行的方法的名称 ----"+method);
        return name.contains("markor.jpa.hello.jpa.controller");
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter,
                                  MediaType mediaType, Class selectedConverterType,
                                  ServerHttpRequest serverHttpRequest,
                                  ServerHttpResponse serverHttpResponse) {
        HttpServletResponse response = ((ServletServerHttpResponse)serverHttpResponse).getServletResponse();
        String code = String.valueOf(response.getStatus());
        System.out.println("code: "+code);
        HttpStatus status = HttpStatus.resolve(response.getStatus());
        System.out.println("HttpStatus: "+status.value());
        String msg = "error";
        if (status != null) {
            msg = status.getReasonPhrase();
        }
        System.out.println("msg: " + msg);
        System.out.println("body: "+body);
        ResponseDTO<Object> responseDto = new ResponseDTO<Object>()
                .setCode(code)
                .setMsg(msg)
                .setData(body);
        System.out.println("selectedConverterType: "+selectedConverterType);

        if (selectedConverterType == StringHttpMessageConverter.class) {
            try {
                return objectMapper.writeValueAsString(responseDto);
            } catch (Exception ex) {
                return body;
            }
        } else {
            return responseDto;
        }
    }

    // 拦截表单提交方式失败时的方法
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(BindException.class)
    public ResponseEntity hello(HttpServletRequest request, HttpServletResponse response, BindException e) throws IOException {
        /*String result = "";
        if (e.hasErrors()) {
            List<ObjectError> errors = e.getAllErrors();
            for (ObjectError error: errors) {
                String objectName = error.getObjectName();
                String message = error.getDefaultMessage();
                result+= objectName+":"+message;
                result += String.format("%s:%s\r\n",objectName, message);
            }
        }
        log.error("Param Exception! ", e);
        System.out.println(e.getMessage());
        return result;*/

        return new ResponseEntity<>(
                new ResponseDTO<>()
                        .setCode("100")
                        .setMsg(e.getMessage().toString())
                        .setData(""),
                HttpStatus.OK);
    }

    /**
     * 拦截RequestBody时的自动映射失败的问题
     * @param request
     * @param response
     * @param e
     * @return
     * @throws IOException
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity hello1(HttpServletRequest request, HttpServletResponse response, MethodArgumentNotValidException e) throws IOException {
        /*String result = "";
        String errorMsg = e.getBindingResult().getFieldErrors().stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .findFirst()
                .orElse(e.getMessage());
        System.out.println("***********   1   **************");
        log.error("Param Exception! ", e);
        System.out.println(e.getMessage());
        return errorMsg;*/

        return new ResponseEntity<>(
                new ResponseDTO<>()
                        .setCode("100")
                        .setMsg(e.getMessage().toString())
                        .setData(""),
                HttpStatus.OK);
    }

    @ExceptionHandler(CommonBizException.class)
    public ResponseEntity commonBizException(CommonBizException e) {
        return new ResponseEntity<>(
                new ResponseDTO<>()
                        .setCode(e.getErrCode())
                        .setMsg(e.getMessage())
                        .setData(""),
                HttpStatus.OK);
    }
}
